#include "Person.h"
#include "PersonSerializer.h"
#include <cstdlib>

namespace etu {
namespace genealogy_tree {

Person::Person() 
    : birthDate(Date::unkown()), deathDate(Date::unkown()) {

    this->firstName = "";
    this->lastName = "";
    this->gender = UNKNOWN_GENDER;
    this->description = "";
    this->photoId = "";
}

Person::Person(const std::string& _firstName, const std::string& _lastName, Gender gender,
        const Date& _birthDate, const Date& _deathDate, 
        const std::string& description, const std::string& photoId)
        throw (IllegalArgumentException)
        : birthDate(_birthDate), deathDate(_deathDate) {

    if(_firstName.empty()) {
        throw IllegalArgumentException("Имя человека должно быть задано");
    }

    if(_lastName.empty()) {
        throw IllegalArgumentException("Фамилия человека должна быть задана");
    }

    if(!Date::isUnkown(_deathDate) && (_deathDate < _birthDate)) {
        throw IllegalArgumentException("Дата смерти не может быть раньше даты рождения человека");
    }

    this->firstName = _firstName;
    this->lastName = _lastName;
    this->gender = gender;
    this->description = description;
    this->photoId = photoId;
}

Person::Person(const Person& orig) 
    : birthDate(orig.birthDate), deathDate(orig.deathDate) {

    this->firstName = orig.firstName;
    this->lastName = orig.lastName;
    this->gender = orig.gender;
    this->description = orig.description;
    this->photoId = orig.photoId;
}

Person::~Person() {
}

Person Person::unknown() {
    Person ret;
    return ret;
}

Person Person::unknownMalePerson() {
    Person ret("", "", MALE_GENDER, Date::unkown(), Date::unkown());
    return ret;
}

Person Person::unknownFemalePerson() {
    Person ret("", "", FEMALE_GENDER, Date::unkown(), Date::unkown());
    return ret;
}

bool Person::isUnkownPerson(const Person& person) {
    return (Date::isUnkown(person.birthDate)
            && Date::isUnkown(person.birthDate)
            && "" == person.lastName
            && "" == person.firstName);
}

const std::string& Person::getFirstName() const {
    return this->firstName;
}

const std::string& Person::getLastName() const {
    return this->lastName;
}

void Person::setFirstName(const std::string& firstName) {
  this->firstName = firstName;
}

void Person::setLastName(const std::string& lastName) {
  this->lastName = lastName;
}

Gender Person::getGender() const {
    return this->gender;
}

void Person::setGender(Gender gender) {
    this->gender = gender;
}

const Date& Person::getBirthDate() const {
    return this->birthDate;
}

void Person::setBirthDate(const Date& birthDate) {
    this->birthDate = birthDate;
}

const Date& Person::getDeathDate() const {
    return this->deathDate;
}

void Person::setDeathDate(const Date& deathDate) {
    this->deathDate = deathDate;
}

const std::string& Person::getDescription() const {
    return this->description;
}

void Person::setDescription(const std::string& description) {
    this->description = description;
}

const std::string& Person::getPhotoId() const {
    return this->photoId;
}

void Person::setPhotoId(const std::string& id) {
    this->photoId = id;
}

bool Person::hasPhoto() const {
	return (!this->photoId.empty());
}

bool Person::isDead()
{
  return !Date::isUnkown(this->deathDate);
}

bool Person::operator==(const Person &person) const {
    return (this->birthDate == person.birthDate)
            && (this->deathDate == person.deathDate)
            && (this->firstName == person.firstName)
            && (this->gender == person.gender)
            && (this->lastName == person.lastName)
            && (this->description == person.description)
            && (this->photoId == person.photoId);
}

bool Person::operator!=(const Person &person) const {
    return (this->birthDate != person.birthDate)
            && (this->deathDate != person.deathDate)
            && (this->firstName != person.firstName)
            && (this->gender != person.gender)
            && (this->lastName != person.lastName)
            && (this->description != person.description)
            && (this->photoId != person.photoId);
}

std::ostream& operator<<(std::ostream& os, const Person& person) {
    PersonSerializer serializer;
    Person* _person = (Person *) &person;

    os << serializer.serialize(_person);

    return os;
}

std::ostream& operator<<(std::ostream& os, const Person* person) {
    PersonSerializer serializer;
    os << serializer.serialize(person);

    return os;
}

std::istream& operator>>(std::istream& is, Person& person) {
    std::string src;

    std::getline(is, src); // TODO

    PersonSerializer serializer;
    Person* _person = serializer.deserialize(src);

    person.birthDate = _person->birthDate;
    person.deathDate = _person->deathDate;
    person.firstName = _person->firstName;
    person.gender = _person->gender;
    person.lastName = _person->lastName;
    person.description = _person->description;
    person.photoId = _person->photoId;

    delete _person;

    return is;
}

std::istream& operator>>(std::istream& is, const Person* person) {
    std::string src;

    std::getline(is, src); // TODO

    PersonSerializer serializer;
    Person* _person = serializer.deserialize(src);

    if(person == NULL) {
        person = new Person(_person->firstName, _person->lastName,
                _person->gender, _person->birthDate, _person->deathDate,
                _person->description, _person->photoId);
    } else {
        Person* notConstPerson = const_cast<Person *>(person);

        notConstPerson->birthDate = _person->birthDate;
        notConstPerson->deathDate = _person->deathDate;
        notConstPerson->firstName = _person->firstName;
        notConstPerson->gender = _person->gender;
        notConstPerson->lastName = _person->lastName;
        notConstPerson->description = _person->description;
        notConstPerson->photoId = _person->photoId;
    }

    delete _person;

    return is;
}

}
}
